package de.koller.oceanFramework.gl.util;

import de.koller.oceanFramework.OceanException;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.*;

public class FrameTexture {

	public static int MIN_FILTER = GL11.GL_LINEAR;
	public static int MAG_FILTER = GL11.GL_LINEAR;
	
	private final int width, height;
	private final int frameBuffer;
	private final int depthBuffer;
	private final int texture;
	
	private FrameTexture( int width, int height ) {
		this.width = width; this.height = height;

		frameBuffer = EXTFramebufferObject.glGenFramebuffersEXT();
		texture = GL11.glGenTextures();
		depthBuffer = EXTFramebufferObject.glGenRenderbuffersEXT();
		
		GL11.glBindTexture( GL11.GL_TEXTURE_2D, 0 );
		EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer );
		
		GL11.glBindTexture( GL11.GL_TEXTURE_2D, texture );
		GL11.glTexParameterf( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, MIN_FILTER );
		GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT, (ByteBuffer)null );
		EXTFramebufferObject.glFramebufferTexture2DEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 
				EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, 
				texture, 0 );
		
		EXTFramebufferObject.glBindRenderbufferEXT( EXTFramebufferObject.GL_RENDERBUFFER_EXT, depthBuffer );
		EXTFramebufferObject.glRenderbufferStorageEXT( EXTFramebufferObject.GL_RENDERBUFFER_EXT,
				EXTPackedDepthStencil.GL_DEPTH_STENCIL_EXT, width, height );
		EXTFramebufferObject.glFramebufferRenderbufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
				EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, 
				depthBuffer ); 
		EXTFramebufferObject.glFramebufferRenderbufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
				EXTFramebufferObject.GL_STENCIL_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, 
				depthBuffer ); 
		
		EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0 );   
	}
	
	public static FrameTexture generate( int width, int height ) {
		if( !GLContext.getCapabilities().GL_EXT_framebuffer_object )
			throw new OceanException( "Your card does not support FrameTexture" );
		
		FrameTexture ft = new FrameTexture( width, height );
		
		MIN_FILTER = GL11.GL_LINEAR;
		MAG_FILTER = GL11.GL_LINEAR;
	
		return ft;
	}
	
	public void bindFBOWithoutClear() {
		GL11.glViewport( 0, 0, width, height );
		GL11.glBindTexture( GL11.GL_TEXTURE_2D, 0 );
		EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, frameBuffer ); 
	}
	
	public void bindFBO() {
		bindFBOWithoutClear();
		clearFBO();
	}
	
	public void clearFBO( float a, float r, float g, float b ) {
		GL11.glClearColor( r, g, b, a );
		GL11.glClear( GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT );
		GL11.glLoadIdentity();
	}
	
	public void clearFBO() {
		clearFBO( 0, 0, 0, 0 );
	}
	
	public void unbindFBO() {
		GL11.glEnable( GL11.GL_TEXTURE_2D );
		GL11.glBindTexture( GL11.GL_TEXTURE_2D, 0 );
		EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0 );
		GL11.glViewport( 0, 0, Display.getWidth(), Display.getHeight() );
		GL11.glClearColor( 0, 0, 0, 0 );
	}
	
	public void bindTexture() {
		GL11.glEnable( GL11.GL_TEXTURE_2D );
		GL11.glBindTexture( GL11.GL_TEXTURE_2D, texture );
	}

	public int getTexture() {
		return texture;
	}

	public int getFrameBuffer() {
		return frameBuffer;
	}
	
}
